﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Xml.Linq;
using System.Xml.Serialization;
using System.IO;
using KonachanChanger.Data;
using System.Threading;

namespace KonachanChanger.API
{
    public class Search
    {
       public int limit = 0;
       public int page = 1;
       public string tags = "";
       public bool ShouldCacheSearch = true;


        public int NumBlocked { get; private set; }
        public int NumLoaded { get; private set; }


        public string URL
        {
            get
            {
                UriBuilder  url = new UriBuilder("http://konachan.com/post/index.xml");
                if (limit > 0)
                    url.AppendQuery("limit=" + limit);
                if (page > 1)
                    url.AppendQuery("page=" + page);
                if (tags != "")
                    url.AppendQuery("tags=" + removeCustomSearches(tags).Replace(' ','+'));
                return url.ToString();
            }
        }

        private string removeCustomSearches(string p)
        {
            var s = p.ToLower().Split(' ');
            StringBuilder sb = new StringBuilder();
            foreach (var t in s)
            {
                if (!t.StartsWith("downloaded:"))
                    sb.Append(t).Append(' ');
            }
            return sb.ToString();
        }

        public posts getPosts()
        {
            WebClient client = new WebClient();
            var localDb = LocalDb.GetInstance();
            XmlSerializer serializer = new XmlSerializer(typeof(posts));
            //if (!localDb.Searches.ContainsKey(tags))
            //    localDb.Searches[tags] = new List<int>();
            Program.Log("Loading API: {0}", URL);
            posts posts;
            using (Stream stream = client.OpenRead(URL))
            {
                posts = serializer.Deserialize(stream) as posts;
            }
            //localDb.SearchMetadata[tags] = new LocalDb.SearchData() { Count = posts.count };
            if (posts.Posts == null)
                posts.Posts = new object[] { };
            Program.Log("Loaded Search: {0}, {1} posts.", URL, posts.Posts.Length);

            try
            {
                List<object> rposts = posts.Posts.ToList();
                for (int i = 0; i < rposts.Count; i++)
                {
                    post p = ((post)rposts[i]);
                    //if (!localDb.Searches[tags].Contains(p.id))
                    //    localDb.Searches[tags].Add(p.id);
                    if (ShouldCacheSearch)
                        localDb.AddPostToSearch(p.id, tags);
                    localDb[p.id] = p;
                    if (localDb.BlockedIds.Contains(p.id))
                    {
                        rposts.RemoveAt(i--);
                        NumBlocked++;
                    }
                    else
                        NumLoaded++;
                    if (_callback != null)
                        _callback.DynamicInvoke(p, this);
                }
                posts.Posts = rposts.ToArray();
            }
            catch (Exception v) { Console.WriteLine(v.ToString()); }
            if (posts.Posts.Length > 1) // If we only had 1 hit, it's not having a second page.
            {
                this.page++;
                try
                {
                    this.getPosts();
                }
                catch (WebException)
                {
                    Thread.Sleep(50);
                    this.getPosts();
                }
            }
            return posts;
        }
        Action<post,Search> _callback = null;
        internal void RegisterCallback(Action<post,Search> action)
        {
            _callback = action;
        }

        internal bool MatchesRating(post post)
        {
            return LocalDb.MatchesRating(post, tags);
        }

    }
}
